package com.belizer.demo.thread;

import java.io.IOException;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.*;

/**
 * 不使用synchronized解决带缓存因式分解器的线程安全问题
 */
public class VolatileCachedFactorizer {
    private volatile OneValueCache oneValueCache = new OneValueCache(null, null);

    public BigInteger[] getFactors(BigInteger bi){
        BigInteger[] factors = oneValueCache.getFactors(bi);

        if (Objects.isNull(factors)) {
            factors = doFactor(bi);
            oneValueCache = new OneValueCache(bi, factors);
        }

        return factors;
    }

    // 因式分解逻辑
    private BigInteger[] doFactor(BigInteger bi) {
        List<BigInteger> factors = new ArrayList<>();
        BigInteger[] factorsArr = {};
        for (BigInteger i = new BigInteger("2"); i.compareTo(bi) <= 0; i = i.add(new BigInteger("1"))) {
            if (bi.remainder(i).equals(new BigInteger("0"))) {
                factors.add(i);
            }
        }
        return factors.toArray(factorsArr);
    }

    private static class OneValueCache {
        private final BigInteger lastNumber;
        private final BigInteger[] lastFactors;

        private OneValueCache(BigInteger bi, BigInteger[] factors) {
            this.lastNumber = bi;
            if (Objects.nonNull(factors)) {
                this.lastFactors = Arrays.copyOf(factors,factors.length);
            }else {
                this.lastFactors = null;
            }
        }

        public BigInteger[] getFactors(BigInteger bi){
            if (Objects.isNull(lastNumber) || !lastNumber.equals(bi)) {
                return null;
            } else {
                return Arrays.copyOf(lastFactors,lastFactors.length);
            }
        }


    }


    public static void main(String[] args) throws InterruptedException, ExecutionException, IOException {
        //验证，多个线程使用该因式分解器，都能获取正确结果
        //使用数 2 3 4 4 6 6 8 8 9 10
        //使用线程池，固定线程池，每个线程执行后打印结果

        ExecutorService executorService = Executors.newFixedThreadPool(10);

        VolatileCachedFactorizer factorizer = new VolatileCachedFactorizer();


        executorService.execute(()->{
            BigInteger[] factors = factorizer.getFactors(new BigInteger("2"));
            System.out.println("当前线程["+Thread.currentThread().getName()+"]，入参["+"2"+"]，结果["+Arrays.toString(factors)+"]");
        });
       executorService.execute(()->{
            BigInteger[] factors = factorizer.getFactors(new BigInteger("3"));
           System.out.println("当前线程["+Thread.currentThread().getName()+"]，入参["+"3"+"]，结果["+Arrays.toString(factors)+"]");

        });
       executorService.execute(()->{
            BigInteger[] factors = factorizer.getFactors(new BigInteger("4"));
           System.out.println("当前线程["+Thread.currentThread().getName()+"]，入参["+"4"+"]，结果["+Arrays.toString(factors)+"]");

        });
       executorService.execute(()->{
            BigInteger[] factors = factorizer.getFactors(new BigInteger("4"));
           System.out.println("当前线程["+Thread.currentThread().getName()+"]，入参["+"4"+"]，结果["+Arrays.toString(factors)+"]");

        });
       executorService.execute(()->{
            BigInteger[] factors = factorizer.getFactors(new BigInteger("6"));
           System.out.println("当前线程["+Thread.currentThread().getName()+"]，入参["+"6"+"]，结果["+Arrays.toString(factors)+"]");

        });
       executorService.execute(()->{
            BigInteger[] factors = factorizer.getFactors(new BigInteger("6"));
           System.out.println("当前线程["+Thread.currentThread().getName()+"]，入参["+"6"+"]，结果["+Arrays.toString(factors)+"]");

        });
       executorService.execute(()->{
            BigInteger[] factors = factorizer.getFactors(new BigInteger("8"));
           System.out.println("当前线程["+Thread.currentThread().getName()+"]，入参["+"8"+"]，结果["+Arrays.toString(factors)+"]");

        });
       executorService.execute(()->{
            BigInteger[] factors = factorizer.getFactors(new BigInteger("8"));
           System.out.println("当前线程["+Thread.currentThread().getName()+"]，入参["+"8"+"]，结果["+Arrays.toString(factors)+"]");

        });
       executorService.execute(()->{
            BigInteger[] factors = factorizer.getFactors(new BigInteger("9"));
           System.out.println("当前线程["+Thread.currentThread().getName()+"]，入参["+"9"+"]，结果["+Arrays.toString(factors)+"]");

        });
       executorService.execute(()->{
            BigInteger[] factors = factorizer.getFactors(new BigInteger("10"));
           System.out.println("当前线程["+Thread.currentThread().getName()+"]，入参["+"10"+"]，结果["+Arrays.toString(factors)+"]");

// executorService.shutdown() 会等待任务执行完毕再关闭线程池
//           try {
//               TimeUnit.SECONDS.sleep(6);
//           } catch (InterruptedException e) {
//               e.printStackTrace();
//           }

       });

//       System.exit(0);
//        Thread.currentThread().join();

        executorService.shutdown();
    }
}
